package com.chatplus.application.processor.channel.chat.chatgpt;

import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import com.chatplus.application.domain.dto.ChatConfigDto;
import com.chatplus.application.domain.entity.basedata.ApiKeyEntity;
import com.chatplus.application.processor.channel.chat.IChatAiProcessorService;
import com.chatplus.application.processor.constant.AIConstants;
import com.chatplus.application.processor.constant.AiPlatformConstants;
import com.chatplus.application.processor.handler.dto.ChatRecordMessage;
import com.chatplus.application.processor.listener.ChatGPTEventSourceListener;
import com.chatplus.application.service.basedata.ApiKeyService;
import com.chatplus.application.service.basedata.ConfigService;
import com.unfbx.chatgpt.OpenAiStreamClient;
import com.unfbx.chatgpt.entity.chat.BaseMessage;
import com.unfbx.chatgpt.entity.chat.ChatCompletion;
import com.unfbx.chatgpt.entity.chat.Message;
import com.unfbx.chatgpt.function.KeyRandomStrategy;
import com.unfbx.chatgpt.interceptor.OpenAILogger;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import com.chatplus.application.processor.AIChannelServiceProvider;

/**
 * ChatGPT 机器人处理器
 *
 * @author chj
 * @date 2023/12/27
 **/
@Service(value = AIChannelServiceProvider.SERVICE_NAME_PRE + AiPlatformConstants.OPEN_AI)
public class ChatGPTProcessor extends IChatAiProcessorService {
    private static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(ChatGPTProcessor.class);

    private final ConfigService configService;
    private final ApiKeyService apiKeyService;

    public ChatGPTProcessor(ConfigService configService, ApiKeyService apiKeyService) {
        this.configService = configService;
        this.apiKeyService = apiKeyService;
    }


    @Override
    public void process(List<ChatRecordMessage> messageContext) {
        List<Message> messages = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(messageContext)) {
            messages = messageContext.stream().map(msg -> Message.builder().content(msg.getPrompt()).role(BaseMessage.Role.USER).build()).collect(Collectors.toList());
        } else {
            Message currentMessage = Message.builder().content("你好").role(BaseMessage.Role.USER).build();
            messages.add(currentMessage);
        }
        String modelName = getSession().getAttributes().get("modelName").toString();
        // 以下为发起请求
        String prompt = messageContext.stream()
                .filter(msg -> msg.getReply() == null)
                .map(ChatRecordMessage::getPrompt)
                .collect(Collectors.joining());
        sendOpenAi(messages, modelName, prompt);
    }

    @Override
    public String getChannel() {
        return AiPlatformConstants.OPEN_AI;
    }

    private void sendOpenAi(List<Message> messages, String modelName, String prompt) {
        ChatConfigDto chatConfigDto = configService.getChatConfig();
        ChatConfigDto.OpenAiBean openAiBean = chatConfigDto.getOpenAi();
        if (openAiBean == null) {
            replyErrorMessage("加载系统配置失败，连接已关闭！！！");
            return;
        }
        List<ApiKeyEntity> apiKeys = apiKeyService.getApiKeys(AiPlatformConstants.OPEN_AI, "chat");
        if (CollectionUtils.isEmpty(apiKeys)) {
            replyErrorMessage("抱歉😔😔😔，系统已经没有可用的 API KEY，请联系管理员！");
            replyErrorMessage(AIConstants.ERROR_MSG);
            replyErrorMessage(AIConstants.ERR_IMG);
            return;
        }
        List<String> apiKeysList = apiKeys.stream().map(ApiKeyEntity::getValue).collect(Collectors.toList());
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new OpenAILogger());
        //!!!!!!测试或者发布到服务器千万不要配置Level == BODY!!!!
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(httpLoggingInterceptor)
                .connectTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(600, TimeUnit.SECONDS)
                .readTimeout(600, TimeUnit.SECONDS).build();
        OpenAiStreamClient openAiStreamClient = OpenAiStreamClient.builder()
                .apiHost(handleHost(openAiBean.getApiUrl()))
                .apiKey(apiKeysList)
                //自定义key使用策略 默认随机策略
                .keyStrategy(new KeyRandomStrategy())
                .okHttpClient(okHttpClient)
                //.authInterceptor(new DynamicKeyOpenAiAuthInterceptor())
                .build();
        ChatCompletion chatCompletion = ChatCompletion.builder()
                .model(modelName)
                .temperature(openAiBean.getTemperature())
                .maxTokens(openAiBean.getMaxTokens())
                .messages(messages)
                .stream(true)
                .build();

        openAiStreamClient.streamChatCompletion(chatCompletion, new ChatGPTEventSourceListener(getSession(), getChannel(), prompt));

    }

    private String handleHost(String url) {
        Pattern pattern = Pattern.compile("(https?://[^/]+/)");
        Matcher matcher = pattern.matcher(url);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }
}
